# Context switch
#
#   void swtch(struct context **old, struct context *new);
# 
# Save current register context in old
# and then load register context from new.

.globl swtch
swtch:                    # 函数调用断点eip位于esp+0
  movl 4(%esp), %eax      # 第一个参数**old，位于esp+4
  movl 8(%esp), %edx      # 第二个参数*new，位于esp+8

  # Save old callee-save registers  # 切换断点的任务执行现场
  pushl %ebp                        # 其中eip作为返回地址已经在堆栈中
  pushl %ebx
  pushl %esi
  pushl %edi

  # Switch stacks
  movl %esp, (%eax)                 # 当前esp保存到旧执行流的context中
  movl %edx, %esp                   # 切换到新的内核栈

  # Load new callee-save registers  # 从内核栈中恢复环境
  popl %edi
  popl %esi
  popl %ebx
  popl %ebp
  ret                               # 相当于弹出context最后一个成员eip
